﻿using System;
using System.Collections.ObjectModel;
using System.Threading;
using CoreWf;
using CoreWf.Expressions;
using CoreWf.Statements;
using CoreWf.Runtime.DurableInstancing;
using CoreWf.XamlIntegration;
using System.Collections.Generic;
using System.IO;

namespace netcoreWF
{
    public class Program
    {
        public static Stream GenerateStreamFromString(string s)
        {
            MemoryStream stream = new MemoryStream();
            StreamWriter writer = new StreamWriter(stream);
            writer.Write(s);
            writer.Flush();
            stream.Position = 0;
            return stream;
        }

        public static Stream GenerateStreamFromFile(string fileName)
        {
            FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            byte[] bytes = new byte[fileStream.Length];
            fileStream.Read(bytes, 0, bytes.Length);
            fileStream.Close();

            Stream stream = new MemoryStream(bytes);
            return stream;
        }

        static void Main(string[] args)
        {
            AutoResetEvent syncEvent = new AutoResetEvent(false);
            AutoResetEvent idleEvent = new AutoResetEvent(false);
            //// no fault expected
            //Console.WriteLine("Invoke with Promo Code {0}, number of kids {1}", "Single", 0);
            //WorkflowInvoker.Invoke(CreateFlowchartWithFaults("Single", 0));

            //// no fault expected
            //Console.WriteLine();
            //Console.WriteLine("Invoke with Promo Code {0}, number of kids {1}", "MNK", 0);
            //WorkflowInvoker.Invoke(CreateFlowchartWithFaults("MNK", 0));

            //// no fault expected
            //Console.WriteLine();
            //Console.WriteLine("Invoke with Promo Code {0}, number of kids {1}", "MWK", 2);
            //WorkflowInvoker.Invoke(CreateFlowchartWithFaults("MWK", 2));

            //// fault expected
            //Console.WriteLine();
            //Console.WriteLine("Invoke with Promo Code {0}, number of kids {1}", "MWK", 0);
            //WorkflowInvoker.Invoke(CreateFlowchartWithFaults("MWK", 0));


            //WorkflowInvoker.Invoke(new MainActivity("hello world"));

            string currDirectory = System.Environment.CurrentDirectory;
            string xamlfileName = currDirectory + "\\XAML\\flightProcesser.xml";
            var settings = new ActivityXamlServicesSettings { CompileExpressions = true };
            var activity = ActivityXamlServices.Load(GenerateStreamFromFile(xamlfileName), settings);
            var inputs = new Dictionary<string, object>();
            inputs.Add("myInput", "InputValue_HelloWorld");
            WorkflowApplication wfapp = new WorkflowApplication(activity,inputs);

            //工作流完成
            wfapp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
            {
                //int output = Convert.ToInt32(e.Outputs["output"]);
                Console.WriteLine($"工作流完成");
                syncEvent.Set();
            };

            //工作流实例进入空闲状态时执行的操作
            wfapp.Idle = delegate (WorkflowApplicationIdleEventArgs e)
            {
                idleEvent.Set();
            };

            wfapp.Aborted = delegate (WorkflowApplicationAbortedEventArgs e) { };
            wfapp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
            {
                Console.WriteLine(e.UnhandledException.ToString());
                return UnhandledExceptionAction.Terminate;
            };

            wfapp.Run();

            Console.WriteLine("\nPress Enter to exit");
            Console.ReadLine();
        }


        private static Activity CreateFlowchartWithFaults(string promoCode, int numKids)
        {
            Variable<string> promo = new Variable<string> { Default = promoCode };
            Variable<int> numberOfKids = new Variable<int> { Default = numKids };
            Variable<double> discount = new Variable<double>();
            DelegateInArgument<DivideByZeroException> ex = new DelegateInArgument<DivideByZeroException>();

            FlowStep discountNotApplied = new FlowStep
            {
                Action = new WriteLine
                {
                    DisplayName = "WriteLine: Discount not applied",
                    Text = "Discount not applied"
                },
                Next = null
            };

            FlowStep discountApplied = new FlowStep
            {
                Action = new WriteLine
                {
                    DisplayName = "WriteLine: Discount applied",
                    Text = "Discount applied "
                },
                Next = null
            };

            FlowDecision flowDecision = new FlowDecision
            {
                Condition = ExpressionServices.Convert<bool>((ctx) => discount.Get(ctx) > 0),
                True = discountApplied,
                False = discountNotApplied
            };

            FlowStep singleStep = new FlowStep
            {
                Action = new Assign
                {
                    DisplayName = "discount = 10.0",
                    To = new OutArgument<double>(discount),
                    Value = new InArgument<double>(10.0)
                },
                Next = flowDecision
            };

            FlowStep mnkStep = new FlowStep
            {
                Action = new Assign
                {
                    DisplayName = "discount = 15.0",
                    To = new OutArgument<double>(discount),
                    Value = new InArgument<double>(15.0)
                },
                Next = flowDecision
            };

            FlowStep mwkStep = new FlowStep
            {
                Action = new TryCatch
                {
                    DisplayName = "Try/Catch for Divide By Zero Exception",
                    Try = new Assign
                    {
                        DisplayName = "discount = 15 + (1 - 1/numberOfKids)*10",
                        To = new OutArgument<double>(discount),
                        Value = new InArgument<double>((ctx) => (15 + (1 - 1 / numberOfKids.Get(ctx)) * 10))
                    },
                    Catches =
                    {
                         new Catch<System.DivideByZeroException>
                         {
                             Action = new ActivityAction<System.DivideByZeroException>
                             {
                                 Argument = ex,
                                 DisplayName = "ActivityAction - DivideByZeroException",
                                 Handler =
                                     new Sequence
                                     {
                                         DisplayName = "Divide by Zero Exception Workflow",
                                         Activities =
                                         {
                                            new WriteLine()
                                            {
                                                DisplayName = "WriteLine: DivideByZeroException",
                                                Text = "DivideByZeroException: Promo code is MWK - but number of kids = 0"
                                            },
                                            new Assign<double>
                                            {
                                                DisplayName = "Exception - discount = 0",
                                                To = discount,
                                                Value = new InArgument<double>(0)
                                            }
                                         }
                                     }
                             }
                         }
                    }
                },
                Next = flowDecision
            };

            FlowStep discountDefault = new FlowStep
            {
                Action = new Assign<double>
                {
                    DisplayName = "Default discount assignment: discount = 0",
                    To = discount,
                    Value = new InArgument<double>(0)
                },
                Next = flowDecision
            };

            FlowSwitch<string> promoCodeSwitch = new FlowSwitch<string>
            {
                Expression = promo,
                Cases =
                {
                   { "Single", singleStep },
                   { "MNK", mnkStep },
                   { "MWK", mwkStep }
                },
                Default = discountDefault
            };

            Flowchart flowChart = new Flowchart
            {
                DisplayName = "Promotional Discount Calculation",
                Variables = { discount, promo, numberOfKids },
                StartNode = promoCodeSwitch,
                Nodes =
                {
                    promoCodeSwitch,
                    singleStep,
                    mnkStep,
                    mwkStep,
                    discountDefault,
                    flowDecision,
                    discountApplied,
                    discountNotApplied
                }
            };

            return flowChart;
        }
    }
}
